package parser_protobuf3

import (
	"fmt"
	"path/filepath"
	"strconv"
	"strings"

	"gitee.com/woodpile/wgs.ths.code.generate/definition"
	"github.com/jhump/protoreflect/desc" //cspell: disable-line
)

func (p *Parser) parseEnums(ctx *definition.Context) error {
	fParseFile := func(dir, filename string) error {
		if definition.GlobalConfig.Verbose {
			fmt.Println("ParseFile ", filepath.Join(dir, filename))
		}

		df := p.getOrNewDFFile(ctx, dir, filename)
		defer ctx.AddDefinedFile(df)

		arrProtoFile, err := protoParser.ParseFiles(df.Path)
		if err != nil {
			return fmt.Errorf("proto parse file %s failed: %w", df.Path, err)
		}
		for _, pf := range arrProtoFile {
			if err := p.parseFileEnums(ctx, pf, df); err != nil {
				return fmt.Errorf("parse file %s content failed: %w", df.Path, err)
			}
		}
		return nil
	}
	for _, dir := range definition.GlobalConfig.Parser.Dir {
		if err := definition.ForeachFileRecursively(dir, p.filterFile, fParseFile); err != nil {
			return err
		}
	}
	return nil
}

func (p *Parser) parseFileEnums(ctx *definition.Context, pf *desc.FileDescriptor, df *definition.DFFile) error {
	for _, pe := range pf.GetEnumTypes() {
		de, err := p.parseProtoEnum(pe)
		if err != nil {
			return fmt.Errorf("parse enum %s failed: %w", pe.GetName(), err)
		}
		de.SourceFile = df.Path
		df.Enums = append(df.Enums, de)
	}
	return nil
}

func (p *Parser) parseProtoEnum(pe *desc.EnumDescriptor) (*definition.DFEnum, error) {
	de := &definition.DFEnum{}

	de.Name = pe.GetName()

	if si := pe.GetSourceInfo(); si != nil {
		if si.GetLeadingComments() != "" {
			de.Comment = strings.TrimSpace(si.GetLeadingComments())
		}
	}

	for _, ev := range pe.GetValues() {
		dev, err := p.parseProtoEnumValue(ev)
		if err != nil {
			return nil, fmt.Errorf("parse enum value %s failed: %w", ev.GetName(), err)
		}
		de.Values = append(de.Values, dev)
	}

	return de, nil
}

func (p *Parser) parseProtoEnumValue(pev *desc.EnumValueDescriptor) (*definition.DFEnumValue, error) {
	dev := &definition.DFEnumValue{}

	dev.Name = pev.GetName()
	dev.Value = strconv.FormatInt(int64(pev.GetNumber()), 10)

	if si := pev.GetSourceInfo(); si != nil {
		if si.GetLeadingComments() != "" {
			dev.Comment = strings.TrimSpace(si.GetLeadingComments())
		}
		if si.GetTrailingComments() != "" {
			if dev.Comment != "" {
				dev.Comment += "\n"
			}
			dev.Comment += strings.TrimSpace(si.GetTrailingComments())
		}
	}

	return dev, nil
}
